package com.gitee.qdbp.general.system.web.shiro.simple;

import org.springframework.beans.factory.annotation.Autowired;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.result.ResponseMessage;
import com.gitee.qdbp.base.controlling.IOperateRecordControlling;
import com.gitee.qdbp.base.shiro.token.FormParamToken;
import com.gitee.qdbp.base.system.model.IAccount;
import com.gitee.qdbp.base.system.model.IAccountType;
import com.gitee.qdbp.base.system.service.IDefaultValueConfig;
import com.gitee.qdbp.base.system.service.IUserTypeConverter;
import com.gitee.qdbp.general.system.api.personnel.model.AccountBean;
import com.gitee.qdbp.general.system.api.personnel.model.UserCoreBean;
import com.gitee.qdbp.general.system.api.personnel.model.VirtualUser;
import com.gitee.qdbp.general.system.api.personnel.service.IUserAuthExecutor;
import com.gitee.qdbp.general.system.error.UserErrorCode;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 账号密码登录
 *
 * @author zhaohuihua
 * @version 160816
 */
public abstract class SimpleAccountLoginRealm extends SimpleAbstractLoginRealm {

    @Autowired
    private IUserAuthExecutor userAuthExecutor;
    @Autowired(required = false)
    protected IOperateRecordControlling operateRecord;

    @Autowired
    protected IDefaultValueConfig defaultValues;
    @Autowired
    protected IUserTypeConverter userTypeConverter;

    protected String getTenantCode(FormParamToken token) {
        String factory = token.getParam("factory");
        if (VerifyTools.isBlank(factory)) {
            factory = defaultValues.getTenantCode();
        }
        return factory;
    }

    protected IAccountType getUserType(FormParamToken token) {
        String type = token.getParam("type");
        if (VerifyTools.isBlank(type)) {
            return defaultValues.getUserType();
        } else {
            return userTypeConverter.convert(type);
        }
    }

    @Override
    protected IAccount doGetAuthenticationInfo(FormParamToken token) throws ServiceException {
        if (operateRecord != null) {
            operateRecord.start();
        }

        // 获取登录参数
        String id = token.getParam("id"); // 登录超时之后的重新登录会传id
        String account = token.getUsername();
        char[] passwords = token.getPassword();
        String password = passwords == null ? null : new String(passwords);

        String tenantCode = getTenantCode(token);
        IAccountType userType = getUserType(token);

        AccountBean ab = new AccountBean(tenantCode, userType, account);
        try {
            UserCoreBean bean;
            if (VerifyTools.isNotBlank(id)) { // ID+password登录
                bean = userAuthExecutor.login(id, password);
            } else { // account+password登录
                IAccountType[] choose = ConvertTools.toArray(defaultValues.getUserTypeChoose(), IAccountType.class);
                bean = userAuthExecutor.login(ab, password, choose);
            }
            bean.getOptions(true).put("DEVELOP", token.getParam("DEVELOP"));
            IAccount user = new LoginUser(bean);
            ResponseMessage returns = new ResponseMessage(user);
            if (operateRecord != null) {
                operateRecord.save(this.getClass(), "doGetAuthenticationInfo", "登录", returns, user);
            }
            return user;
        } catch (ServiceException e) {
            //  为防止不断尝试来恶意套取用户名, 不返回用户不存在, 只返回用户名或密码错误
            ServiceException se;
            if (e.getCode().equals(UserErrorCode.USER_LOGIN_PASSWORD_ERROR.getCode())) {
                se = new ServiceException(UserErrorCode.USER_OR_PASSWORD_ERROR);
            } else if (e.getCode().equals(UserErrorCode.USER_NOT_EXIST.getCode())) {
                se = new ServiceException(UserErrorCode.USER_OR_PASSWORD_ERROR);
            } else {
                se = e;
            }
            ResponseMessage returns = new ResponseMessage(e);
            VirtualUser operator = new VirtualUser();
            operator.setTenantCode(tenantCode);
            operator.setUserType(userType);
            operator.setNickName(account);
            if (operateRecord != null) {
                operateRecord.save(this.getClass(), "doGetAuthenticationInfo", "登录", returns, operator);
            }
            throw se;
        }
    }
}
